package com.gitee.lougnib.hellowebim.module.chatroom.controller;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import com.gitee.lougnib.hellowebim.common.dto.RestResponseDto;
import com.gitee.lougnib.hellowebim.common.mybatis.entity.ChatRoomMessageEntity;
import com.gitee.lougnib.hellowebim.module.chatroom.constant.ChatRoomConsts;
import com.gitee.lougnib.hellowebim.module.chatroom.model.ChatRoomMessageDto;
import com.gitee.lougnib.hellowebim.module.chatroom.service.ChatRoomService;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@RestController
@RequestMapping(ChatRoomConsts.PATH_ROOT + "/rest")
public class ChatRoomRestController {

    @Autowired
    private ChatRoomService chatRoomService;

    //private final static Cache<String, String> chache = CacheBuilder<String, String>.newBuilder().

    private final static long[] SLEEP_TIME = { 0L };

    @RequestMapping("init")
    public Object init() {
        return RestResponseDto.ok(toDtoList(chatRoomService.getAllMessages()));
    }

    @RequestMapping("sendMessage")
    public Object sendMessage(@RequestBody Map<String, Object> params, HttpServletRequest request) {
        String senderId = request.getHeader("x-user-id");
        String message = MapUtils.getString(params, "message");
        Long messageId = chatRoomService.saveMessage(senderId, message);
        // 有新消息，恢复默认的刷新时间
        SLEEP_TIME[0] = 0L;
        return RestResponseDto.ok(messageId);
    }

    @RequestMapping("getNewestMessages")
    public Object getNewestMessages(@RequestBody Map<String, Object> params) {
        long lastMessageId = getLastMessageId(params);
        return RestResponseDto.ok(toDtoList(chatRoomService.getNewestMessages(lastMessageId)));
    }

    @RequestMapping("async/getNewestMessages")
    public DeferredResult<ResponseEntity<?>> handleReqDefResult(@RequestBody Map<String, Object> params,
            HttpServletRequest request) {
        DeferredResult<ResponseEntity<?>> output = new DeferredResult<>(5 * 60 * 1000L);

        /**
         * 5 秒刷新一次数据，直至超时或发生错误。
         */
        final long lastMessageId = getLastMessageId(params);
        final boolean[] processCompleted = { false };
        final String visitorId = request.getHeader(ChatRoomConsts.HEADER_KEY_VISITOR_ID);
        output.onTimeout(() -> {
            processCompleted[0] = true;
            //log.debug("last message id = {}, visitor id = {}, is timeout.", lastMessageId, visitorId);
            output.setResult(
                    ResponseEntity.status(HttpStatus.OK)
                            .body(RestResponseDto.ok()));
        });

        output.onError((Throwable t) -> {
            processCompleted[0] = true;
            //log.debug("last message id = {}, visitor id = {}, has error.", lastMessageId, visitorId);
            output.setErrorResult(
                    ResponseEntity.status(HttpStatus.OK)
                            .body(RestResponseDto.ok()));
        });
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        executorService.submit(() -> {
            List<ChatRoomMessageEntity> messages = null;
            try {
                //log.debug("last message id = {}, visitor id = {}, internal = {}", lastMessageId, visitorId, SLEEP_TIME[0]);
                while (CollectionUtils.isEmpty(messages)) {
                    messages = chatRoomService.getNewestMessages(lastMessageId);

                    if (CollectionUtils.isEmpty(messages)) {
                        Thread.sleep(SLEEP_TIME[0]);

                        if (SLEEP_TIME[0] < 30000L) {
                            SLEEP_TIME[0] = SLEEP_TIME[0] + 100L;
                        }
                    }

                    if (processCompleted[0]) {
                        break;
                    }
                }
                //log.debug("last message id = {}, visitor id = {}, internal = {}", lastMessageId, visitorId, SLEEP_TIME[0]);
            } catch (InterruptedException e) {
                log.error(e.getMessage(), e);
            }
            output.setResult(ResponseEntity.ok(RestResponseDto.ok(toDtoList(messages))));
        });

        return output;
    }

    private long getLastMessageId(Map<String, Object> params) {
        String strLastMessageId = MapUtils.getString(params, "lastMessageId");
        long lastMessageId = 0;
        if (StringUtils.isNotBlank(strLastMessageId)) {
            lastMessageId = Long.parseLong(strLastMessageId);
        }
        return lastMessageId;
    }

    private List<ChatRoomMessageDto> toDtoList(List<ChatRoomMessageEntity> entityList) {
        List<ChatRoomMessageDto> dtoList = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(entityList)) {
            entityList.forEach(entity -> {
                ChatRoomMessageDto dto = new ChatRoomMessageDto();
                dto.setId(entity.getId());
                dto.setMsg(entity.getMessageContent());
                dto.setCtime(entity.getSendTime());
                dto.setType(entity.getMessageType());
                dto.setSid(entity.getSenderId());
                dtoList.add(dto);
            });
        }

        return dtoList;
    }
}
